/* 
 *  Copyright 2012 CodeMagi, Inc.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.codemagi.servlets;

import com.codemagi.util.Utils;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.log4j.Logger;

/**
 *  Forces incoming requests to use https.
 *
 *  @version 1.0
 *  @author August Detlefsen for CodeMagi, Inc.
 */
public final class SecureFilter implements Filter {

    Logger log = Logger.getLogger(this.getClass());

    //CONSTANTS
    public static final String STD_HTTP_PORT  = "80";
    public static final String STD_HTTPS_PORT = "443";

    //MEMBERS
    private String httpPort         = null;
    private String httpsPort        = null;
    private String httpsHeaderName  = null;
    private String httpsHeaderValue = null;

    private FilterConfig config     = null;


    public void init(FilterConfig config) 
	throws ServletException {

	this.config = config;

        httpPort         = config.getInitParameter("http.port");
        if (httpPort == null) httpPort = STD_HTTP_PORT;

        httpsPort        = config.getInitParameter("https.port");
	if (httpsPort == null) httpsPort = STD_HTTPS_PORT;

        httpsHeaderName  = config.getInitParameter("https.headername");
        httpsHeaderValue = config.getInitParameter("https.headervalue");

	log.debug("headerName: " + httpsHeaderName + " headerValue: " + httpsHeaderValue);
    }


    public void destroy() {
	this.config = null;
    }


    public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) 
	throws ServletException, IOException {

	HttpServletRequest request = (HttpServletRequest)req;

	if ( !isSecure(request) ) {
	    String vQueryString = request.getQueryString();
	    String vServer      = request.getServerName();

	    String vPageUrl     = (String)request.getAttribute("javax.servlet.forward.request_uri");
	    if (Utils.isEmpty(vPageUrl)) vPageUrl = request.getRequestURI();

	    StringBuffer vRedirect = new StringBuffer("");
	    vRedirect.append("https://");
	    if (httpsPort == null || httpsPort.trim().length() == 0 || httpsPort.equals(STD_HTTPS_PORT)) {
		vRedirect.append(vServer + vPageUrl);

	    } else {
		vRedirect.append(vServer + ":" + httpsPort + vPageUrl);

	    }

	    if (vQueryString != null) {
		vRedirect.append("?");
		vRedirect.append(vQueryString);
	    }

	    log.debug("attempting to redirect to: " + vRedirect);

	    ((HttpServletResponse)response).sendRedirect(vRedirect.toString());

	} else {
            chain.doFilter(request, response);
        }

	return;
    }

    /**
     * Returns true if this request is secure, either by the <code>request.isSecure()</code> method or 
     * by checking for the presence of a request header.
     */
    private boolean isSecure(HttpServletRequest request) {
	
	log.debug("SecureTag.isSecure() called...");

	//first try the java internal method
	if (request.isSecure()) {
	    log.debug("Connection secure according to ServletRequest");
	    return true;
	}

	//if there is an ssl accelerator in use, check for the existence of 
	//headers indicating that the accelerator has processed the request
        boolean secure = false;
        if ( !Utils.isEmpty(httpsHeaderName) ) {

            String headerValue = request.getHeader(httpsHeaderName);
	    log.debug("headerValue      = " + headerValue);
	    log.debug("httpsHeaderValue = " + httpsHeaderValue);

	    if (!Utils.isEmpty(headerValue)) {
		log.debug("EQUAL: " + headerValue.contains(httpsHeaderValue));
		secure = headerValue.contains(httpsHeaderValue); 
	    }
        }

        log.debug("Connection secure = " + secure);
        return secure;
    }


}
